/* 
    1. Promise是一个类
        所以要通过class定义一个类
    2. new Promise() 参数是一个执行器exec函数
        所以构造函数参数要传入一个函数
    3. exec执行器的函数是resovle和reject
        所以定义两个函数resolve和reject
    4. promise 有三种状态
        所以定义三个常量 PENDING,FULILLED,REJECTED
    5. 执行器根据状态调用对应的方法
        成功则绑定数据
        失败则绑定失败报错信息
    ---------------- 完成·简版promise  -----------
    1. 处理Promise中的异步操作 ✔
        setTimeout()
        同步时（等待状态）保存成功/失败回调
        执行异步时对应状态时再执行
    -----------------------------------------------
    1. 增加then()多次调用 ✔
        使用数组保存成功/失败回调，执行时遍历执行
        借助数组的shift()方法
    -----------------------------------------------
    1. 实现then()的链式调用 ✔
        1. 关键在于then() 执行后返回一个promsie对象的实例
        2. 下一个then()要使用上一个then()执行的结果
        3. 封装resolvePromise()方法
            分别处理普通返回值 和 返回promise对象的

    -----------------------------------------------
    promise对象循环调用问题处理 ✔
        如果是循环调用则提示html一样的报错
        'Chaining cycle detected for promise #<Promise>'
    -----------------------------------------------
    实现Promise.resolve()方法 ✔
        如果参数为promsie对象，则直接返回
        如果参数为其他类型数据，则通过创建promise对象实例进行包装
     -----------------------------------------------
    实现Promise.all()方法   --- 掌握不熟练，按照正确代码仿敲的
    ------------------------------------------------
    实现返回promise对象默认值 ✔
    ------------------------------------------------
    实现catch()方法 ✔
        通过try..catch 捕获所有地方的错误
        定义catch()方法,直接调用reject()
     -----------------------------------------------
    实现finally()方法  --- 掌握不熟练，按照正确代码仿敲的
    ----------------- 完成 ------------------------
    // 暴露出该模块
*/
const STATUS = {
  PENDING: 0,
  FULFILLED: 1,
  REJECTED: 2,
};
class MyPromise {
  constructor(exec) {
      try {
          exec(this.resolve, this.reject);
      } catch (error) {
        this.reject(error)
      }
  }
  successCallback = [];
  failCallback = [];
  status = STATUS.PENDING;

  resolve = (value) => {
    if (this.status != STATUS.PENDING) {
      return;
    }
    this.status = STATUS.FULFILLED;
    this.value = value;
    // this.successCallback && this.successCallback(this.value);
    while (this.successCallback.length)
      this.successCallback.shift()(this.value);
  };
  reject = (error) => {
    if (this.status != STATUS.PENDING) {
      return;
    }
    this.status = STATUS.REJECTED;
    this.error = error;
    // this.failCallback && this.failCallback(this.error);
    while (this.failCallback.length) this.failCallback.shift()(this.error);
  };
  then(successCallback, failCallback) {
    // 默认返回promise对象
    successCallback = successCallback ? successCallback : value => value;
    failCallback = failCallback ? failCallback: error => { throw error };
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === STATUS.FULFILLED) {
        // 同步逻辑
        let x = successCallback(this.value);
        resolvePromise(promise2,x, resolve, reject);
      } else if (this.status === STATUS.REJECTED) {
        // 同步逻辑
        failCallback(this.error);
      } else {
        // 异步逻辑
        this.successCallback.push(successCallback);
        this.failCallback.push(failCallback);
      }
    });
    return promise2;
  }
  finally (callback) {
    return this.then(value => {
      return MyPromise.resolve(callback()).then(() => value);
    }, reason => {
      return MyPromise.resolve(callback()).then(() => { throw reason })
    })
  }
  catch (failCallback) {
    return this.then(undefined, failCallback)
  }
  static resolve (value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve => resolve(value));
  }
  static all (array) {
    let result = [];
    let index = 0;
    return new MyPromise((resolve, reject) => {
      function addData (key, value) {
        result[key] = value;
        index++;
        if (index === array.length) {
          resolve(result);
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          // promise 对象
          current.then(value => addData(i, value), reason => reject(reason))
        }else {
          addData(i, array[i]);
        }
      }
    })
  }
}
function resolvePromise(newpromise,x, resolve, reject) {
    if(newpromise === x){
        // 如果promise循环调用，则返回报错
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>')); 
    }
  if (x instanceof MyPromise) {
    x.then(resolve, reject);
  } else {
      resolve(x)
  }
}
// module.exports = MyPromise
